import { saveAs } from "file-saver";
// import { startLoading } from '@/axios/index.js';

import * as THREE from "three";
import { GUI } from "three/examples/jsm/libs/lil-gui.module.min.js";
import { MeshLambertMaterial } from "three/src/materials/MeshLambertMaterial.js";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { MTLLoader } from "three/examples/jsm/loaders/MTLLoader.js";
import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader.js";
import { RGBELoader } from "three/examples/jsm/loaders/RGBELoader.js";
import { Sky } from "three/examples/jsm/objects/Sky.js";
import { RoomEnvironment } from "three/examples/jsm/environments/RoomEnvironment.js";
import { randomString } from "@/utils/index.js";
// webGL对象配置
export const webglOBJ = {
  renderDom: null,
  Scene: null, // 场景
  camera: null, // 相机
  renderer: null, // 渲染器
  senceAdd(objList = []) {
    objList.forEach((v) => {
      webglOBJ.Scene.add(v);
    });
  },
  // 加载模型
  loadMIT(mtl, obj, callBack) {
    // const $load = startLoading();
    new MTLLoader().load(mtl, function(materials) {
      materials.preload();
      new OBJLoader().setMaterials(materials).load(
        obj,
        function(object) {
          object.traverse((child) => {
            child.castShadow = false;
            child.$msg = "man";
            child.receiveShadow = true;
          });
          webglOBJ.Scene.add(object);
        },
        function(load) {
          if (load.loaded == load.total) {
            $load.close();
          }
        }
      );
    });
  },
  // 创建场景
  createSence(renderDom, color = 0xbfd1e5) {
    this.renderDom = renderDom;
    webglOBJ.Scene = new THREE.Scene();
    // webglOBJ.Scene.background = new Color(color);
    // webglOBJ.Scene.background = new Color(color).setHSL(1, 0, 1);
    webglOBJ.Scene.fog = new THREE.Fog(webglOBJ.Scene.background, 1, 5000);
    return webglOBJ.Scene;
  },
  // 正交投影相机
  createOrthographicCamera({ fov, aspect, near, far, position } = {}) {
    const { width, height } = this.renderDom.getBoundingClientRect();
    const k = width / height; //窗口宽高比
    const s = 150; //三维场景显示范围控制系数，系数越大，显示的范围越大
    let camera = new OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
    camera.position.set(position.x, position.y, position.z);
    camera.lookAt(webglOBJ.Scene.position); // 视角
    camera.enableDamping = true; // 视角
    webglOBJ.camera = camera; // 视角
    return webglOBJ.camera;
  },
  // 创建摄像机
  createCamera({ fov, aspect, near, far, position } = {}) {
    const { width, height } = this.renderDom.getBoundingClientRect();
    let camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
    camera.position.set(position.x, position.y, position.z);
    camera.lookAt(webglOBJ.Scene.position); // 视角
    camera.enableDamping = true; // 视角
    webglOBJ.camera = camera; // 视角spotLight
    return webglOBJ.camera;
  },
  createRenderer(color = 0xffffff) {
    let renderer = new THREE.WebGLRenderer({
      antialias: true,
      alpha: true,
      // 如果想保存three.js canvas画布上的信息，注意设置preserveDrawingBuffer
      preserveDrawingBuffer: true,
    });

    const { width, height } = this.renderDom.getBoundingClientRect();
    renderer.setSize(width, height);
    renderer.setPixelRatio(window.devicePixelRatio);
    // renderer.setClearColor(new Color(color));
    renderer.outputEncoding = THREE.sRGBEncoding;
    renderer.toneMapping = THREE.ACESFilmicToneMapping;
    renderer.toneMappingExposure = 0.4;
    renderer.shadowMap.enabled = true;
    this.renderDom.appendChild(renderer.domElement);
    webglOBJ.renderer = renderer;
    return webglOBJ.renderer;
  },
  createPlane(textureLoaderUrl, textureNormalUrl) {
    let planeGeometry = new PlaneGeometry(100, 100, 100, 1); // 平面网格
    let textureLoader = new TextureLoader();
    let texture = textureLoader.load(textureLoaderUrl);
    let textureNormal = textureLoader.load(textureNormalUrl);
    // 加载高光贴图
    // let planeMaterial = new MeshLambertMaterial({
    //   // specular: 0xff0000,//高光部分的颜色
    //   shininess: 30, //高光部分的亮度，默认30
    //   map: texture, // 普通纹理贴图
    //   roughness: 0.3,
    //   lightMap: textureNormal,
    //   // normalMap: textureNormal, //法线贴图
    //   bumpScale: 3,
    // }); // 材质对象Material
    let planeMaterial = new MeshLambertMaterial({ color: 0x333 });
    let plane = new Mesh(planeGeometry, planeMaterial);
    plane.rotation.x = -0.5 * Math.PI;
    plane.position.x = 0;
    plane.position.y = 0;
    plane.receiveShadow = true;
    return plane;
  },
  createBoxGeometry(textureLoaderUrl, { x, y, z }) {
    // 创建立方体
    let textureLoader = new TextureLoader();
    let textureNormal = textureLoader.load(textureLoaderUrl);
    let boxGeometry = new BoxGeometry(10, 10, 10, 200);
    let texture1 = textureLoader.load(textureLoaderUrl);
    let boxGeometryMaterial = new MeshLambertMaterial({
      // specular: 0xff0000,//高光部分的颜色
      shininess: 10, //高光部分的亮度，默认30
      normalScale: new Vector2(2.2, 2.2),
      map: texture1, // 普通纹理贴图
      normalMap: textureNormal, //法线贴图
      bumpMap: textureNormal,
      bumpScale: 0.3,
    });
    let box = new Mesh(boxGeometry, boxGeometryMaterial);
    box.position.x = x;
    box.position.y = y;
    box.position.z = z;
    box.castShadow = false;
    return box;
  },
  // 聚光光源
  createSpotLight(
    { x = 0, y = 0, z = 0 },
    color = 0xffffff,
    width = 10,
    height = 10
  ) {
    // 点光源
    let spotLight = new SpotLight(color);
    spotLight.position.set(x, y, z);
    spotLight.angle = Math.PI / 4;
    spotLight.castShadow = true;
    spotLight.shadow.mapSize.width = 0;
    spotLight.shadow.mapSize.height = 0;

    const userData = {
      is3Dmode: true,
      modeId: randomString("modeId"),
      type: "light",
      addFunction: "addSpotLight",
    };
    spotLight.userData = userData;

    spotLight.name = "聚光灯";
    let helper = new SpotLightHelper(spotLight);
    helper.position.set({ x, y, z });
    // webglOBJ.Scene.add(helper);
    return spotLight;
  },
  // 穹顶灯
  createHemisphereLight(color = 0xffffff, color1 = 0x080820, s = 0.5) {
    const hemisphereLight = new HemisphereLight(color, color1, s);
    const userData = {
      is3Dmode: true,
      modeId: randomString("modeId"),
      addFunction: "addHemisphereLight",
      type: "light",
    };
    hemisphereLight.userData = userData;
    hemisphereLight.name = "半球光";
    return hemisphereLight;
  },
  // 平行光
  createDirectionalLight({ x, y, z }, s = 1) {
    // 平行光
    let directionalLight = new DirectionalLight(0xffffff, s);
    const userData = {
      is3Dmode: true,
      modeId: randomString("modeId"),
      type: "light",
      addFunction: "addDirectionalLight",
    };
    directionalLight.userData = userData;

    directionalLight.name = "平行光";
    let helper = new DirectionalLightHelper(directionalLight);
    helper.position.set({ x, y, z });
    const dirhelp = new CameraHelper(directionalLight.shadow.camera);
    helper.userData.is3Dmode = true;
    helper.userData.lightHelp = true;
    const d = 30; //阴影范围
    // webglOBJ.Scene.add(dirhelp);
    // webglOBJ.Scene.add(helper);
    // 设置光源的方向：通过光源position属性和目标指向对象的position属性计算
    directionalLight.position.set(x, y, z);
    directionalLight.shadow.camera.near = 0.5; // default
    directionalLight.shadow.camera.far = 10000; // default
    directionalLight.shadow.bias = -0.00005; // 设置柔性阴影效果，避免出现阴影燥点
    directionalLight.shadow.mapSize.width = 81920; // 去掉对应阴影面积，否则会出现一个长方形的阴影面积
    directionalLight.shadow.mapSize.height = 81920;
    directionalLight.shadow.camera.left = -d;
    directionalLight.shadow.camera.right = d;
    directionalLight.shadow.camera.top = d;
    directionalLight.shadow.camera.bottom = -d;
    // 方向光指向对象网格模型mesh2，可以不设置，默认的位置是0,0,0
    directionalLight.castShadow = true;
    directionalLight.shadow.radius = 5;
    directionalLight.receiveShadow = true;
    return directionalLight;
  },
  // 创建平面光
  createRectAreaLight(
    color = 0xffffff,
    intensity = 1,
    width = 100,
    height = 100,
    { x = 0, y = 0, z = 0 }
  ) {
    const rectLight = new RectAreaLight(color, intensity, width, height);
    rectLight.position.set(x, y, z);
    const userData = {
      is3Dmode: true,
      modeId: randomString("modeId"),
      addFunction: "addRectAreaLight",
      type: "light",
    };
    rectLight.userData = userData;
    rectLight.name = "区域光";
    rectLight.userData.lightHelp = true;
    rectLight.castShadow = true;
    rectLight.receiveShadow = true;
    rectLight.lookAt(0, 0, 0);
    // rectLightHelper = new RectAreaLightHelper(rectLight);
    // webglOBJ.Scene.add(rectLightHelper);
    return rectLight;
  },
  // 创建点光源
  createPointLight(color = 0xffffff, s = 1, distance = 0) {
    const pointLight = new PointLight(color, s, distance);
    const userData = {
      is3Dmode: true,
      modeId: randomString("modeId"),
      addFunction: "addPointLight",
      type: "light",
    };
    pointLight.userData = userData;
    pointLight.name = "点光源";
    pointLight.castShadow = true;
    pointLight.shadow.mapSize.width = 0;
    pointLight.shadow.mapSize.height = 0;
    const shadowCameraHelper = new CameraHelper(pointLight.shadow.camera);
    let helper = new PointLightHelper(pointLight);
    helper.userData.is3Dmode = true;
    helper.userData.lightHelp = true;
    // webglOBJ.Scene.add(helper);
    // webglOBJ.Scene.add(shadowCameraHelper);
    return pointLight;
  },
  // 环境光
  createAmbient(color = 0xffffff, s = 1) {
    let ambient = new AmbientLight(color, s);
    const userData = {
      is3Dmode: true,
      modeId: randomString("modeId"),
      addFunction: "addAmbient",
      type: "light",
    };
    ambient.userData = userData;
    ambient.name = "环境光";
    // let helper = new AmbientLightHelper(ambient);
    // webglOBJ.Scene.add(helper);
    return ambient;
  },
  createDatGui() {
    let gui = {
      bump: 0.03,
      animation: false,
    };
    let datGui = new GUI();
    //将设置属性添加到gui当中，gui.add(对象，属性，最小值，最大值）
    datGui.add(gui, "bump", -1, 1).onChange(function(e) {
      box.material.bumpScale = e;
    });
    datGui.add(gui, "animation");
    return datGui;
  },
  // 创建Hdr
  createHdrEnv(url, sence) {
    return new Promise(function(resolve, reject) {
      new RGBELoader().load(url, (texture) => {
        texture.mapping = EquirectangularReflectionMapping;
        sence.background = texture;
        sence.environment = texture;
        resolve();
      });
    });
  },
  // 设置房间环境效果，均匀灯光显示
  createRoomEnvironment() {
    const pmremGenerator = new THREE.PMREMGenerator(webglOBJ.renderer);
    // sence.background = new THREE.Color( 0xdeebed );
    webglOBJ.Scene.environment = pmremGenerator.fromScene(
      new RoomEnvironment()
    ).texture;
  },
  // 白天天空环境背景
  createSunSky() {
    const hemiLight = new THREE.HemisphereLight(0xffffff, 0xffffff, 0.6);
    hemiLight.color.setHSL(0.6, 1, 0.6);
    hemiLight.groundColor.setHSL(0.095, 1, 0.75);
    // SKYDOME
    const vertexShader = document.getElementById("vertexShader").textContent;
    const fragmentShader = document.getElementById("fragmentShader")
      .textContent;

    const uniforms = {
      topColor: { value: new THREE.Color(0x0077ff) },
      bottomColor: { value: new THREE.Color(0xffffff) },
      offset: { value: 33 },
      exponent: { value: 0.6 },
    };
    uniforms["topColor"].value.copy(hemiLight.color);
    webglOBJ.Scene.fog.color.copy(uniforms["bottomColor"].value);
    const skyGeo = new THREE.SphereGeometry(2500, 0, 0);
    const skyMat = new THREE.ShaderMaterial({
      uniforms: uniforms,
      vertexShader: vertexShader,
      fragmentShader: fragmentShader,
      side: THREE.BackSide,
    });
    skyGeo.visible = false;
    const sky = new THREE.Mesh(skyGeo, skyMat);
    sky.userData.isSky = true; // 天空背景标识
    return sky;
  },
  // 创建太阳落山环境
  createNightSky() {
    // Add Sky
    // Add Sky
    const vm = this;
    let sky = new Sky();
    sky.scale.setScalar(450000);
    let sun = new THREE.Vector3(100, 2000, 100);
    /// GUI
    const effectController = {
      turbidity: 10,
      rayleigh: 3,
      mieCoefficient: 0.005,
      mieDirectionalG: 0.7,
      elevation: 2,
      azimuth: 80,
      exposure: this.renderer.toneMappingExposure,
    };
    function guiChanged() {
      const uniforms = sky.material.uniforms;
      uniforms["turbidity"].value = effectController.turbidity;
      uniforms["rayleigh"].value = effectController.rayleigh;
      uniforms["mieCoefficient"].value = effectController.mieCoefficient;
      uniforms["mieDirectionalG"].value = effectController.mieDirectionalG;
      const phi = THREE.MathUtils.degToRad(90 - effectController.elevation);
      const theta = THREE.MathUtils.degToRad(effectController.azimuth);
      sun.setFromSphericalCoords(1, phi, theta);
      uniforms["sunPosition"].value.copy(sun);
      webglOBJ.renderer.toneMappingExposure = effectController.exposure;
    }
    guiChanged();
    sky.userData.isSky = true; // 天空背景标识
    return sky;
  },
  // 晚上全黑
  createBlackSky() {
    // SKYDOME
    const vertexShader = document.getElementById("vertexShader").textContent;
    const fragmentShader = document.getElementById("fragmentShader")
      .textContent;

    const uniforms = {
      topColor: { value: new THREE.Color(0x000000) },
      bottomColor: { value: new THREE.Color(0xffffff) },
      offset: { value: 800 },
      exponent: { value: 0.8 },
    };
    // uniforms['topColor'].value.copy(hemiLight.color);
    webglOBJ.Scene.fog.color.copy(uniforms["bottomColor"].value);
    const skyGeo = new THREE.SphereGeometry(2500, 0, 0);
    const skyMat = new THREE.ShaderMaterial({
      uniforms: uniforms,
      vertexShader: vertexShader,
      fragmentShader: fragmentShader,
      side: THREE.BackSide,
    });
    skyGeo.visible = false;
    const sky = new THREE.Mesh(skyGeo, skyMat);
    sky.userData.isSky = true; // 天空背景标识
    return sky;
  },
  // 创建控制轴
  createControls() {
    let controls = new OrbitControls(webglOBJ.camera, webglOBJ.renderDom);
    controls.maxPolarAngle = (0.9 * Math.PI) / 2; // 最大滚动角度
    controls.enableDamping = true; // 开启阻尼运动，controls 必须在场景render的时候调用 controls.update();

    // controls.autoRotate = true;
    // controls.enablePan = false;

    // controls.enableDamping = true;
    // controls.dampingFactor = 0.65;
    // controls.dampingFactor = .55;
    // controls.autoRotate = true;
    /*
    // 如果使用animate方法时，将此函数删除
    //controls.addEventListener( 'change', render );
    // 使动画循环使用时阻尼或自转 意思是否有惯性
    controls.enableDamping = true;
    //动态阻尼系数 就是鼠标拖拽旋转灵敏度
    //controls.dampingFactor = 0.25;
    //是否可以缩放
    controls.enableZoom = true;
    //是否自动旋转
    controls.autoRotate = false;
    //设置相机距离原点的最远距离
    controls.minDistance = 50;
    //设置相机距离原点的最远距离
    controls.maxDistance = 200;
    //是否开启右键拖拽
    controls.enablePan = true;
    */
    return controls;
  },
  // 中心坐标线
  createAxisHelper() {
    let axisHelper = new THREE.AxesHelper(250);
    return axisHelper;
  },
  // 初始化webGL对象
  webglRender(Scene, camera) {
    webglOBJ.renderer.render(Scene, camera);
    window.requestAnimationFrame(webglOBJ.webglRender);
  },
};

/**
 * 添加标签：dom方式
 * @param {*} targePosition ：需要传递当前标签的位置
 * @param {*} targetId ：标签对应的dom的唯一ID，暂且用时间戳代替，避免重复
 * @param {*} innerHTML ：标签对应html
 */
export function labelTag(camera, targePosition, targetId, innerHTML, webGLdom) {
  const { width, height } = webGLdom.getBoundingClientRect();
  let worldVector = new Vector3(
    targePosition.x,
    targePosition.y,
    targePosition.z
  );
  let vector = worldVector.project(camera);
  let halfWidth = width / 2,
    halfHeight = height / 2;
  let x = Math.round(vector.x * halfWidth + halfWidth);
  let y = Math.round(-vector.y * halfHeight + halfHeight);
  /**
   * 更新立方体元素位置
   */
  let div = document.getElementById(targetId);
  if (!div) return;
  let hg = div.getBoundingClientRect().height;
  div.style.left = x + "px";
  div.style.top = y - hg + "px";
  // div.innerHTML = `uuid:${innerHTML.uuid}`;
}

// 获取模型表面点的空间三维坐标
export function getPointRay(
  scene,
  camera,
  width = window.innerWidth,
  height = window.innerHeight,
  offsetLeft = 0,
  offsetTop = 0
) {
  const event = window.event;
  // 当渲染容器位置不在页面window左上角和顶部对齐的时候需要减去对应的偏移量
  const windowX = event.clientX - offsetLeft; //鼠标单击位置横坐标
  const windowY = event.clientY - offsetTop; //鼠标单击位置纵坐标
  let res = { point: null, mesh: null };

  let x = (windowX / width) * 2 - 1; //标准设备横坐标
  let y = -(windowY / height) * 2 + 1; //标准设备纵坐标
  let standardVector = new Vector3(x, y, 0.5); //标准设备坐标
  //标准设备坐标转世界坐标
  let worldVector = standardVector.unproject(camera);
  let ray = worldVector.sub(camera.position).normalize();
  //创建射线投射器对象
  let raycaster = new Raycaster(camera.position, ray);

  //返回射线选中的对象, 过滤掉不是场景中的模型
  const objects = scene.children.filter(
    (v) => v.type == "Scene" || v.userData.is3Dmode
  );
  let intersects = raycaster.intersectObjects(objects, true);
  console.log(intersects, "----点击的点位坐标----");
  if (intersects.length > 0) {
    // 必须type = 'Mesh'的三维空间点代表是模型上的点，如果不过滤可能会点击的时候并不是模型的点
    const p = intersects.find((v) => v.object && v.object.type == "Mesh");
    let point = p ? p.point : null; //射线在模型表面拾取的点坐标
    let mesh = p ? p.object : null;
    res = { point, mesh, intersects };
  }
  return res;
}

// 空间坐标转二维坐标
export function transPosition(position) {
  let world_vector = new Vector3(position.x, position.y, position.z);
  let vector = world_vector.project(camera);
  let halfWidth = window.innerWidth / 2,
    halfHeight = window.innerHeight / 2;
  return {
    x: Math.round(vector.x * halfWidth + halfWidth),
    y: Math.round(-vector.y * halfHeight + halfHeight),
  };
}

// 深拷贝对象
export function deepCopyObject(obj) {
  var newObj = {};
  if (obj && typeof obj == "object") {
    for (let key in obj) {
      if (obj.hasOwnProperty(key)) {
        if (obj[key] && typeof obj[key] == "object") {
          newObj[key] = deepFn(obj[key]);
        } else {
          newObj[key] = obj[key];
        }
      }
    }
  }
  return newObj;
}

// 点击获取对应的3d模型
export function getClick3DModle(sence, camera) {
  document.removeEventListener("click", clickEvent);
  document.addEventListener("click", clickEvent, false);
  // 监听点击事件查看点击的元素
  let raycaster = new Raycaster();
  let mouse = new Vector2();
  let modle = {};
  // 点击了哪个模型
  function clickEvent(event) {
    if (event.target.tagName == "CANVAS") {
      mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
      mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
      sence.updateMatrixWorld(true);
      // 通过鼠标点的位置和当前相机的矩阵计算出raycaster
      raycaster.setFromCamera(mouse, camera);
      // 获取raycaster直线和所有模型相交的数组集合
      const objects = sence.children.filter(
        (v) => v.type == "Scene" || v.userData.is3Dmode
      );
      let intersects = raycaster.intersectObjects(objects, true);
      if (intersects[0]) {
        modle = intersects[0];
      }
    }
  }
  return modle;
}

export function findParent3DObjct(objs) {
  let res = {};
  // 递归寻找导入的父节点场景设置对应的坐标平移轴
  function findNode(obj) {
    if (obj && obj.userData && obj.userData.is3Dmode) {
      res = obj;
    } else {
      if (obj && obj.parent) {
        findNode(obj.parent);
      }
    }
  }
  findNode(objs);
  return res;
}

// 保存json文件
export const saveDataAsJson = function(json, fileName) {
  const blob = new Blob([JSON.stringify(json, null, 2)], {
    type: "text/plain;charset = utf-8",
  });
  saveAs(blob, fileName, { autoBom: false });
};

// 通过鼠标点击屏幕选中模型
export const chooseModelByClick = (
  event,
  sence,
  camera,
  renderer,
  width = window.innerWidth,
  height = window.innerHeight
) => {
  // 监听点击事件查看点击的元素
  const renderDom = renderer.domElement.parentNode;
  let intersects = null;
  let raycaster = new Raycaster();
  let mouse = new Vector2();
  if (event.target.className == renderDom.className) {
    mouse.x = (event.clientX / width) * 2 - 1;
    mouse.y = -(event.clientY / height) * 2 + 1;
    sence.updateMatrixWorld(true);
    // 通过鼠标点的位置和当前相机的矩阵计算出raycaster
    raycaster.setFromCamera(mouse, camera);
    /**
     * 获取raycaster直线和所有模型相交的数组集合，
     * v.type == 'Scene' 必须要过滤掉类型为场景的模型，
     * 类型为场景的模型则为3D软件导入的模型，否者会出现很多奇怪的问题 ，比如点击模型但是无法获取显示对应的移动坐标轴
     **/
    intersects = raycaster.intersectObjects(
      sence.children.filter((v) => v.type == "Scene" || v.userData.is3Dmode),
      true
    );

    if (intersects[0]) {
      let obj = intersects[0];
      const chooseModel = findParent3DObjct(obj.object);
      return chooseModel;
    }
  }
};

// 获取场景的视角
export const getSenceView = () => {
  const camera = window.$WEBGL.camera;
  const controls = window.$WEBGL.controls;
  const view = {
    _camera: {
      position: {
        x: camera.position.x,
        y: camera.position.y,
        z: camera.position.z,
      },
      rotation: {
        x: camera.rotation.x,
        y: camera.rotation.y,
        z: camera.rotation.z,
      },
    },
    _controls: {
      x: controls.target.x,
      y: controls.target.y,
      z: controls.target.z,
    },
  };

  if (camera && controls) {
    return view;
  } else {
    return {};
  }
};

// 模型设置不透明度和颜色效果
export const setModelBlueMaterial = (
  model = "",
  emissive = "#004efb",
  transparent = true,
  opacity = 0.15
) => {
  // 遍历元素添加对应阴影效果
  model &&
    model.traverse((v) => {
      console.log(v, "v--=-");
      if (v.isMesh) {
        v.material.emissive = emissive
          ? new Color(emissive)
          : new Color(0, 0, 0);
        v.material.transparent = transparent;
        v.material.opacity = opacity;
      }
    });
  return model;
};
